package com.example.common.util;

import com.example.common.exception.BadJwtException;
import io.jsonwebtoken.*;

import java.util.HashMap;
import java.util.Map;

public class JwtUtils {
    public static final String CLAIMS_KEY_NAME = "name";
    public static final String CLAIMS_KEY_EXPIRES_IN = "expiresIn";

    /**
     * @param key
     * @param token
     * @return
     */
    public static String getUserNameFromToken(String key, String token) throws BadJwtException {
        Claims claims = getClaimsFromToken(key, token);
        return claims.get(CLAIMS_KEY_NAME).toString();
    }

    /**
     *
     * @param key
     * @param token
     * @return millisecond
     */
    public static long getExpireInFromToken(String key, String token) throws BadJwtException {
        Claims claims = getClaimsFromToken(key, token);
        return (long) claims.get(CLAIMS_KEY_EXPIRES_IN);
    }

    /**
     * @param key
     * @param token
     * @param username
     * @return
     */
    public static boolean validate(String key, String token, String username) throws BadJwtException {
        final String userNameFromToken = getUserNameFromToken(key, token);
        final Long expiresIn = getExpireInFromToken(key, token);

        return (
                username.equals(userNameFromToken)
                        && !isExpired(expiresIn));
    }

    /**
     * @param key
     * @param username
     * @param expiresIn milliseconds
     * @return
     */
    public static String generateToken(String key, String username, long expiresIn) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIMS_KEY_NAME, username);
        claims.put(CLAIMS_KEY_EXPIRES_IN, System.currentTimeMillis() + expiresIn);

        return Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS512, key)
                .compact();
    }

    private static boolean isExpired(long expireIn) {
        return System.currentTimeMillis() > expireIn;
    }

    private static Claims getClaimsFromToken(String key, String token) throws BadJwtException {
        try {
            return Jwts.parser()
                    .setSigningKey(key)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (ExpiredJwtException e) {
            throw new BadJwtException("Expired jwt");
        } catch (UnsupportedJwtException e) {
            throw new BadJwtException("Unsupported Jwt");
        } catch (MalformedJwtException e) {
            throw new BadJwtException("Malformed Jwt");
        } catch (SignatureException e) {
            throw new BadJwtException("Bad signature");
        } catch (IllegalArgumentException e) {
            throw new BadJwtException("Illegal argument");
        }
    }
}